// License Notification
//======================================================
// Copyright (c) 2010 Channel Intelligence Inc.
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// which accompanies this distribution, and is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// ======================================================




using System;
using System.IO;
using System.Collections;
using System.ComponentModel;
using System.Configuration.Install;
using System.Diagnostics;
using Microsoft.Win32;
using CIP4.Common;

namespace SetupConfig
{
    [RunInstaller(true)]
    public partial class ConfigInstaller : Installer
    {
        StreamWriter _setupLog;

        public ConfigInstaller()
        {
            InitializeComponent();
        }

        public override void Uninstall(IDictionary savedState)
        {
            try
            {
                base.Uninstall(savedState);
                string location = GetLocation(Context.Parameters["assemblypath"]);
                _setupLog = new StreamWriter(Path.Combine(location, "Setup.log"));
                //string startupLocation = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.StartMenu), "Programs\\Startup");
                DeleteTool("CIP4 4 Browser");
                DeleteTool("CIP4 4 Serializer Builder");
                RunInstallerUtil(location, true);
                _setupLog.Write("Removing CIP4_HOME");
                Environment.SetEnvironmentVariable("CIP4_HOME", null, EnvironmentVariableTarget.Machine);
                string xmlFileName = Globals.ConnectionsFileLocation;
                if (File.Exists(xmlFileName))
                {
                    string text = File.ReadAllText(xmlFileName).ToLower();
                    if (text.Contains("cassandra") || text.Contains("mongo"))
                        System.Windows.Forms.MessageBox.Show("If you have installed anything using the CIP4.Installer you will have to uninstall them manually");
                }
            }
            catch (Exception ex)
            {
                if (_setupLog != null)
                {
                    _setupLog.WriteLine("Exeption during uninstall");
                    _setupLog.WriteLine(ex.ToString());
                }
            }
            finally
            {
                if (_setupLog != null)
                    _setupLog.Close();
            }
        }
        
// ReSharper disable RedundantOverridenMember
        public override void Install(IDictionary stateSaver)
        {
            base.Install(stateSaver);
        }
// ReSharper restore RedundantOverridenMember
        
        public override void Commit(IDictionary savedState)
        {
            //System.Windows.Forms.MessageBox.Show("Starting Commit at " + Context.Parameters["assemblypath"]);
            base.Commit(savedState);
            try
            {
                string location = GetLocation(Context.Parameters["assemblypath"]);
                if (string.IsNullOrEmpty(location))
                {
                    _setupLog.WriteLine(
                        "Cannot find assemblypath in setup commit so cannot set CIPL_HOME - cipl will not work until this is fixed");
                    return;
                }
// ReSharper disable PossibleNullReferenceException
                string ciplHome = new DirectoryInfo(location).Parent.FullName;
// ReSharper restore PossibleNullReferenceException
                _setupLog = new StreamWriter(Path.Combine(location, "Setup.log"));
                _setupLog.WriteLine(string.Format("-- Installing CIP4 4 at {0} on {1} {2}", 
                    location, DateTime.Now.ToShortDateString(), DateTime.Now.ToLongTimeString())); 

                _setupLog.Write(string.Format("Setting CIP4_HOME to {0}", ciplHome));
                Environment.SetEnvironmentVariable("CIP4_HOME", ciplHome, EnvironmentVariableTarget.Machine);

                _setupLog.WriteLine("-- Adding Visual Studio tools");
                _setupLog.WriteLine("-- CIP4 Browser 4 " + Path.Combine(location, "CIP4.Browser.exe") + " \"$(BinDir)$(TargetName)$(TargetExt)\"");
                AddTool("CIP4 4 Browser", Path.Combine(location, "CIP4.Browser.exe"), "\"$(BinDir)$(TargetName)$(TargetExt)\"");
                _setupLog.WriteLine("-- CIP4 4 Serializer Builder " + Path.Combine(location, "CIP4.CMD.exe") + " /a build /l information /af \"$(BinDir)$(TargetName)$(TargetExt)\"");
                AddTool("CIP4 4 Serializer Builder", Path.Combine(location, "CIP4.CMD.exe"), "/a build /l information /af \"$(BinDir)$(TargetName)$(TargetExt)\"");
            }
            catch (Exception ex)
            {
                _setupLog.WriteLine("-- Unexpected Exception during ConfigInstaller");
                _setupLog.WriteLine(ex.ToString());
            }
            finally
            {
                if (_setupLog != null)
                    _setupLog.Close();
            }
        }

        private void DeleteTool(string title)
        {
            try
            {
                const string key = "HKEY_CURRENT_USER\\Software\\Microsoft\\VisualStudio\\9.0\\External Tools";
                RegistryKey vskey = Registry.CurrentUser.OpenSubKey(key);
                if (vskey == null)
                    return;

                int value = Convert.ToInt32(Registry.GetValue(key, "ToolNumKeys", null));
                for (int i = 0; i < value; i++)
                {
                    string oldTitle = (string)Registry.GetValue(key, "ToolTitle" + i, string.Empty);
                    if (oldTitle == title)
                    {
                        vskey.DeleteSubKey("ToolArg" + value);
                        vskey.DeleteSubKey("ToolCmd" + value);
                        vskey.DeleteSubKey("ToolTitle" + value);
                        SetRegKey(key, "ToolNumKeys", (value - 1).ToString());
                        _setupLog.WriteLine(string.Format("-- {0} has been deleted", title));
                        return;
                    }
                }
            }
            catch (Exception ex)
            {
                _setupLog.WriteLine("-- Error deleting Visual Studio Tool " + title);
                _setupLog.WriteLine(ex.ToString());
            }
        }

        private void AddTool(string title, string cmd, string arg)
        {
            try
            {
                const string key = "HKEY_CURRENT_USER\\Software\\Microsoft\\VisualStudio\\9.0\\External Tools";
                int value = Convert.ToInt32(Registry.GetValue(key, "ToolNumKeys", null));
                for (int i = 0; i < value; i++)
                {
                    string oldTitle = (string)Registry.GetValue(key, "ToolTitle" + i, string.Empty);
                    if (oldTitle == title)
                    {
                        _setupLog.WriteLine(string.Format("-- {0} is already registered", cmd));
                        return;
                    }
                }
                SetRegKey(key, "ToolArg" + value, arg);
                SetRegKey(key, "ToolCmd" + value, cmd);
                SetRegKey(key, "ToolTitle" + value, title);
                SetRegKey(key, "ToolNumKeys", (value + 1).ToString());
            }
            catch (Exception ex)
            {
                _setupLog.WriteLine("-- Error Adding Visual Studio Tool");
                _setupLog.WriteLine(title + " " + cmd + " " + arg + Environment.NewLine + ex);
            }
        }

        private void SetRegKey(string key, string valueName, object value)
        {
            string regArg = string.Empty;
            try
            {
                Registry.SetValue(key, valueName, value);
                regArg = string.Format("ADD \"{0}\" /f /v \"{1}\" /d \"{2}\"", key, valueName, value);
                _setupLog.WriteLine(string.Format("reg.exe {0}", regArg));
            }
            catch (Exception ex)
            {
                _setupLog.WriteLine("-- Error setting registry key");
                _setupLog.WriteLine(regArg);
                _setupLog.WriteLine(ex.ToString());
                return;
            }
        }

        private void RunInstallerUtil(string where, bool uninstall)
        {
            try
            {
                ProcessStartInfo startInfo = new ProcessStartInfo {WorkingDirectory = where};
                string installExe =
                    string.Format("{0}\\Microsoft.NET\\Framework\\v2.0.50727\\InstallUtil.exe", 
// ReSharper disable PossibleNullReferenceException
                    new DirectoryInfo(Environment.SystemDirectory).Parent.FullName);
// ReSharper restore PossibleNullReferenceException
                startInfo.FileName = installExe;
                startInfo.Arguments = string.Format("{0} {1}", uninstall ? "/u" : string.Empty, where + "CIP4.dll");
                startInfo.CreateNoWindow = true;
                startInfo.WindowStyle = ProcessWindowStyle.Hidden;
                Console.WriteLine(installExe + " " + where + "CIP4.dll");
                Process proc = Process.Start(startInfo);
                if (!proc.WaitForExit(20000))
                {
                    _setupLog.WriteLine("-- InstallUtil.exe failed to terminate before timeout (20 seconds)");
                }
            }
            catch (Exception ex)
            {
                _setupLog.WriteLine("-- Error running InstallUtil");
                _setupLog.WriteLine(ex.ToString());
                return;
            }
        }

        private static string GetLocation(string fromPath)
        {
            string result = fromPath.Substring(0, fromPath.LastIndexOf("\\"));
            return result.Replace("\"", "");
        }
    }
}
